#include "PageCache.h"
#include"ObjectPool.h"
PageCache PageCache::_instan;
// 获取k个页的span
Span *PageCache::newpage(size_t K)
{
    // 都没有,向系统申请一个128page span 然后切分
    assert(K > 0);
    if(K >= MAX_SPANS-1){//大于128页
        void*ptr=SystemAlloc(K);
        //Span *span = new Span();
        Span *span = _spanPool.New();
        span->_pageID = (PageID)ptr >> PAGE_SHIFT;
        span->_n = K;
        _idSpanmap[span->_pageID] = span;
        return span;
    }
    // 检查k页是否有span
    if (!this->_spanLists[K].Empty())
    {
        // 有span,直接返回
        Span*kspan=this->_spanLists[K].PopFront();
         for (PageID i = 0; i < kspan->_n; i++)
                {
                    _idSpanmap[kspan->_pageID + i] = kspan;
                }
                return kspan;
    }
    else
    {
        // 检查后面的桶有没有span
        for (size_t i = K; i < MAX_SPANS; i++)
        {
            if (!this->_spanLists[i].Empty())
            {
                // 有span,切分
                Span *nSpan = _spanLists[i].PopFront();
                Span *kspan = _spanPool.New();
                kspan->_pageID = nSpan->_pageID;
                kspan->_n = K;
                nSpan->_pageID += K;
                nSpan->_n -= K;
                _spanLists[nSpan->_n].PushFront(nSpan);
                // 存储首尾页号和Span的映射
                _idSpanmap[kspan->_pageID] = kspan;
                _idSpanmap[nSpan->_pageID + K - 1] = nSpan;
                // 建立id和Span的映射，方便central cache回收小块内存，查找对应的span
                for (PageID i = 0; i < kspan->_n; i++)
                {
                    _idSpanmap[kspan->_pageID + i] = kspan;
                }
                return kspan;
            }
        }
        // 都没有,向系统申请一个128page span 然后切分
        Span *bigSpan = new Span();
        void *ptr = SystemAlloc(MAX_SPANS - 1);
        bigSpan->_pageID = (int64_t)ptr >> PAGE_SHIFT;
        bigSpan->_n = MAX_SPANS - 1;
        _spanLists[bigSpan->_n].PushFront(bigSpan);
        return newpage(K);
    }
}
Span *PageCache::MapObjectTospan(void *obj)
{
    // 计算页号
    PageID pageID = ((PageID)obj >> PAGE_SHIFT);
    std::unique_lock<std::mutex> lock(_pagemtx);
    auto it = this->_idSpanmap.find(pageID);
    if (it != this->_idSpanmap.end())
    {
        // 找到了span
        return it->second;
    }
    else
    {
        assert(false);
        return nullptr;
    }
}
void PageCache::ReleaseToPageCache(Span *span)
{
    // 对span前后的页进行合并，缓解外碎片问题
    if(span->_n>MAX_SPANS-1){
        void* ptr = (void*)(span->_pageID << PAGE_SHIFT);
        SystemFree(ptr);
        //delete span;
        _spanPool.Delete(span);
        return;
    }
    std::lock_guard<std::mutex> lock(mtx);
    {
        while (1)
        {
            PageID pageID = span->_pageID - 1;
            auto it = this->_idSpanmap.find(pageID);

            if(it == this->_idSpanmap.end()){
                break;
            }
            Span *prevSpan = it->second;
            if(prevSpan->_isUse==true){
                break;
            }
            //不合并超过128个页的span
            if(prevSpan->_n + span->_n >= MAX_SPANS-1){
                break;
            }
            //合并
           span->_n += prevSpan->_n;
           span->_pageID = prevSpan->_pageID;
           _spanLists[prevSpan->_n].Erase(prevSpan);
           this->_idSpanmap.erase(prevSpan->_pageID);
           delete prevSpan;
            //更新映射
        }
        //向后合并
        while(1){
            PageID pageID = span->_pageID + span->_n-1;
            if(pageID >= (1<<32))break;
            auto it = this->_idSpanmap.find(pageID);

            if(it == this->_idSpanmap.end()){
                break;
            }
            Span *prevSpan = it->second;
            if(prevSpan->_isUse==true){
                break;
            }
            //不合并超过128个页的span
            if(prevSpan->_n + span->_n >= MAX_SPANS-1){
                break;
            }
            //合并
           span->_n += prevSpan->_n;
           _spanLists[prevSpan->_n].Erase(prevSpan);
           _idSpanmap.erase(prevSpan->_pageID);
           delete prevSpan;
            //更新映射
        }
        _spanLists[span->_n].PushFront(span);
        //更新映射
        span->_isUse=false;
        _idSpanmap[span->_pageID] = span;
        _idSpanmap[span->_pageID + span->_n - 1]=span;
    }
}